package com.molan.molan_music.service.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.molan.molan_music.config.SecurityConfig;
import com.molan.molan_music.dao.RoleDao;
import com.molan.molan_music.dao.UserDao;
import com.molan.molan_music.dto.TokenCreateRequest;
import com.molan.molan_music.dto.UserCreateRequest;
import com.molan.molan_music.dto.UserDto;
import com.molan.molan_music.dto.UserUpdateRequest;
import com.molan.molan_music.entity.Role;
import com.molan.molan_music.entity.User;
import com.molan.molan_music.enums.Gender;
import com.molan.molan_music.exception.BizException;
import com.molan.molan_music.exception.ExceptionType;
import com.molan.molan_music.mapper.RoleMapper;
import com.molan.molan_music.mapper.UserMapper;
import com.molan.molan_music.service.UserService;
import com.molan.molan_music.vo.RoleVo;
import com.molan.molan_music.vo.UserVo;
import com.molan.molan_music.vo.pageVo.PageRequestVo;
import com.molan.molan_music.vo.pageVo.PageResultVo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;
    @Resource
    private UserDao userDao;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private RoleDao roleDao;

    @Resource
    private RoleMapper roleMapper;

    @Override
    public PageResultVo search(PageRequestVo pageQuery) {
        if(pageQuery.getPageNum()==0){
            pageQuery.setPageNum(1);
        }
        if (pageQuery.getPageSize()==0){
            pageQuery.setPageSize(15);
        }
        List<User> users = userDao.listByEntity(new User(), pageQuery.getPageNum(), pageQuery.getPageSize(), null, null);

        List<UserVo> userVoList = users.stream().map(userMapper::usertoVo).collect(Collectors.toList());

        for (UserVo userVo : userVoList) {
            List<Role> roleList = roleDao.getauThorities(userVo.getUsername());
            List<RoleVo> collect = roleList.stream().map(roleMapper::toVo1).collect(Collectors.toList());
            userVo.setRoleVoList(collect);
        }
        return pagInate(userVoList, pageQuery);
    }
    public PageResultVo pagInate(List<UserVo> dataList, PageRequestVo pageQuery){
        int pageNum = pageQuery.getPageNum();
        int pageSize = pageQuery.getPageSize();
        int x =  pageNum * pageSize;
        int x0 = (pageNum - 1) * pageSize;
        if(x>=dataList.size()){
            x=dataList.size();
        }
        List<UserVo> alarmRecordList0 = new ArrayList<>();
        for (int i = x0 ; i < x; i++) {
            alarmRecordList0.add(dataList.get(i));
        }
        PageResultVo pageResult = new PageResultVo();
        pageResult.setPageNum(pageNum);
        pageResult.setPageSize(pageSize);
        if((dataList.size() % pageSize) > 0) {
            pageResult.setTotalPages((dataList.size()/pageSize) + 1);
        }
        else if((dataList.size() % pageSize) == 0) {
            pageResult.setTotalPages(dataList.size()/pageSize);
        }
        pageResult.setTotalSize(dataList.size());
        pageResult.setDatas(alarmRecordList0);
        return pageResult;
    }

    @Override
    public UserDto addUser(UserCreateRequest userCreateDto) {
        checkUsername(userCreateDto.getUsername());
        checkGender(userCreateDto);
        User entity = userMapper.createEntity(userCreateDto);
        entity.setUserId(UUID.randomUUID().toString().replace("-",""));
        entity.setCreateTime((int) (System.currentTimeMillis()/1000));
        entity.setUpdateTime((int) (System.currentTimeMillis()/1000));
        entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        int insert = userDao.insert(entity, null);
        User user = userDao.getByEntity(entity, null);

        UserDto userDto = userMapper.toDto(user);
        return userDto;
    }

    private void checkGender(UserCreateRequest userCreateDto) {
        String female = Gender.FEMALE.toString();
        String male = Gender.MALE.toString();

        if(female.equals(userCreateDto.getGender())){
            return;
        }else if(male.equals(userCreateDto.getGender())){
            return;
        }else {
            userCreateDto.setGender(Gender.UNKNOWN.toString());
        }
    }

    @Override
    public User loadUserByUsername(String username) {
        User user = userDao.selectByName(username);
        if(Objects.isNull(user)){
            throw new BizException(ExceptionType.USER_NOT_FOUND);
        }
        return user;
    }

    @Override
    public UserDto getUserById(String id) {
        User user = userDao.getUserById(id);
        if(Objects.isNull(user)){
            throw new BizException(ExceptionType.USER_NOT_FOUND);
        }
        return userMapper.toDto(user);
    }

    @Override
    public UserDto updateUser(String id, UserUpdateRequest userUpdateRequest) {
        User user1 = userDao.getUserById(id);
        if(Objects.isNull(user1)){
            throw new BizException(ExceptionType.USER_NOT_FOUND);
        }
        User user = userMapper.updateEntity(userUpdateRequest);
        user.setUserId(id);
        user.setUpdateTime((int) (System.currentTimeMillis()/1000));
        int update = userDao.update(user, true, null);
        User userById = userDao.getUserById(id);
        return userMapper.toDto(userById);
    }

    @Override
    public int deleteUser(String id) {
        User user1 = userDao.getUserById(id);
        if(Objects.isNull(user1)){
            throw new BizException(ExceptionType.USER_NOT_FOUND);
        }
        int i = userDao.deleteById(id, null);
        return i;
    }

    private void checkUsername(String username){
        User user = userDao.selectByName(username);
        if(!Objects.isNull(user)){
            throw new BizException(ExceptionType.USER_NAME_DUPLICATION);
        }
    }

    @Override
    public String tokenCreate(TokenCreateRequest tokenCreateRequest) {
        User user = loadUserByUsername(tokenCreateRequest.getUsername());
        if(!passwordEncoder.matches(tokenCreateRequest.getPassword(), user.getPassword())){
            throw new BizException(ExceptionType.USER_PASSWORD_NOT_MATCH);
        }
        if(!user.isEnabled()){
            throw new BizException(ExceptionType.USER_NOT_ENABLED);
        }
        if(!user.isAccountNonLocked()){
            throw new BizException(ExceptionType.USER_NOT_LOCKED);
        }

        String token = JWT.create()
                .withSubject(user.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() + SecurityConfig.EXPIRATION_TIME))
                .sign(Algorithm.HMAC512(SecurityConfig.SECRET.getBytes()));
        token = SecurityConfig.TOKEN_PREFIX+token;
        return token;
    }

    @Override
    public UserDto getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        User user = loadUserByUsername(authentication.getName());
        return userMapper.toDto(user);
    }

    @Override
    public List<Role> getauThorities(String username) {
        return roleDao.getauThorities(username);
    }
}
